# @FileName  :  signup.py
# @Time      :  2025/7/28 22:34
# @Author    :  Ayanami
# @info      :  报名相关的CRUD操作

from typing import List, Optional, Tuple
from datetime import datetime,timezone
from tortoise.exceptions import IntegrityError
from app.models.models import SignUp, EnrollmentRecord, Course, Student
from app.schemas.signup import (
    SignUpCreate,
    SignUpUpdate,
    EnrollmentRecordResponse,
    EnrollmentRecordCreate,
    SignUpWithDetailsResponse,
    EnrollmentRecordWithDetailsResponse
)


class SignUpCRUD:
    """报名CRUD操作"""

    @staticmethod
    async def create(signup_data: SignUpCreate) -> SignUp:
        """创建报名"""
        # 检查课程是否存在
        course = await Course.get_or_none(id=signup_data.course_id, is_deleted=False)
        if not course:
            raise ValueError("课程不存在")

        # 检查时间逻辑
        if signup_data.start_date >= signup_data.end_date:
            raise ValueError("报名开始时间必须早于结束时间")

        signup_dict = signup_data.model_dump()
        course_id = signup_dict.pop('course_id')

        signup = await SignUp.create(
            course_id=course_id,
            **signup_dict
        )
        return signup

    @staticmethod
    async def get_by_id(signup_id: int) -> Optional[SignUp]:
        """根据ID获取报名"""
        return await SignUp.get_or_none(id=signup_id, is_deleted=False)

    @staticmethod
    async def get_by_id_with_details(signup_id: int) -> Optional[SignUpWithDetailsResponse]:
        """根据ID获取报名详细信息"""
        signup = await SignUp.get_or_none(id=signup_id, is_deleted=False).prefetch_related(
            'course__teacher',
            'course__agent',
            'enrollments__student'
        )

        if not signup:
            return None

        # 获取当前报名人数
        enrollment_count = await EnrollmentRecord.filter(signup_id=signup_id, is_deleted=False).count()

        # 构造响应数据
        enrollments = []
        for enrollment in await signup.enrollments.filter(is_deleted=False):
            student = await enrollment.student
            enrollments.append(EnrollmentRecordResponse(
                id=enrollment.id,
                signup_id=enrollment.signup_id,
                student_id=enrollment.student_id,
                signup_time=enrollment.signup_time
            ))

        course = await signup.course
        teacher = await course.teacher
        agent = await course.agent

        return SignUpWithDetailsResponse(
            id=signup.id,
            start_date=signup.start_date,
            end_date=signup.end_date,
            max_capacity=signup.max_capacity,
            course_id=signup.course_id,
            created_at=signup.created_at,
            updated_at=signup.updated_at,
            current_enrollment_count=enrollment_count,
            course_title=course.title,
            teacher_name=teacher.name,
            agent_name=agent.name,
            enrollments=enrollments
        )


    @staticmethod
    async def get_list(
            page: int = 1,
            page_size: int = 10,
            course_id: Optional[int] = None,
            status: Optional[str] = None  # "upcoming", "ongoing", "ended"
    ) -> Tuple[List[SignUpWithDetailsResponse], int]:
        """获取报名列表"""
        query = SignUp.filter(is_deleted=False)

        # 按课程筛选
        if course_id:
            query = query.filter(course_id=course_id, is_deleted=False)

        # 按状态筛选
        now = datetime.now()
        if status == "upcoming":
            query = query.filter(start_date__gt=now, is_deleted=False)
        elif status == "ongoing":
            query = query.filter(start_date__lte=now, end_date__gte=now, is_deleted=False)
        elif status == "ended":
            query = query.filter(end_date__lt=now, is_deleted=False)

        # 计算总数
        total = await query.count()

        # 分页查询
        signups = await query.prefetch_related(
            'course__teacher',
            'course__agent'
        ).offset((page - 1) * page_size).limit(page_size).order_by('-created_at')

        # 构造响应数据
        result = []
        for signup in signups:
            enrollment_count = await EnrollmentRecord.filter(signup_id=signup.id, is_deleted=False).count()
            course = await signup.course
            teacher = await course.teacher
            agent = await course.agent

            result.append(SignUpWithDetailsResponse(
                id=signup.id,
                start_date=signup.start_date,
                end_date=signup.end_date,
                max_capacity=signup.max_capacity,
                course_id=signup.course_id,
                created_at=signup.created_at,
                updated_at=signup.updated_at,
                current_enrollment_count=enrollment_count,
                course_title=course.title,
                teacher_name=teacher.name,
                agent_name=agent.name,
                enrollments=[]
            ))

        return result, total

    @staticmethod
    async def update(signup_id: int, signup_data: SignUpUpdate) -> Optional[SignUp]:
        """更新报名"""
        signup = await SignUp.get_or_none(id=signup_id, is_deleted=False)
        if not signup:
            return None

        update_data = signup_data.model_dump(exclude_unset=True)

        # 如果更新了课程ID，检查课程是否存在
        if 'course_id' in update_data:
            course = await Course.get_or_none(id=update_data['course_id'], is_deleted=False)
            if not course:
                raise ValueError("课程不存在")

        # 检查时间逻辑
        start_date = update_data.get('start_date', signup.start_date)
        end_date = update_data.get('end_date', signup.end_date)
        if start_date >= end_date:
            raise ValueError("报名开始时间必须早于结束时间")

        # 处理course_id字段
        if 'course_id' in update_data:
            course_id = update_data.pop('course_id')
            update_data['course_id'] = course_id

        await signup.update_from_dict(update_data)
        await signup.save()
        return signup

    @staticmethod
    async def delete(signup_id: int) -> bool:
        """删除报名"""
        signup = await SignUp.get_or_none(id=signup_id, is_deleted=False)
        if not signup:
            return False

        # 检查是否有报名记录
        enrollment_count = await EnrollmentRecord.filter(signup_id=signup_id, is_deleted=False).count()
        if enrollment_count > 0:
            raise ValueError("存在报名记录，无法删除")
        signup.is_deleted = True
        await signup.save(update_fields=["is_deleted", "updated_at"])
        return True


# 修改后的完整 EnrollmentRecordCRUD 类
class EnrollmentRecordCRUD:
    """报名记录CRUD操作"""

    @staticmethod
    async def create(enrollment_data: EnrollmentRecordCreate) -> EnrollmentRecord:
        """创建报名记录"""
        # 检查报名是否存在
        signup = await SignUp.get_or_none(id=enrollment_data.signup_id, is_deleted=False)
        if not signup:
            raise ValueError("报名不存在")

        # 检查学员是否存在
        student = await Student.get_or_none(id=enrollment_data.student_id, is_deleted=False)
        if not student:
            raise ValueError("学员不存在")

        # 检查报名时间
        now = datetime.now(timezone.utc)
        if now < signup.start_date:
            raise ValueError("报名尚未开始")
        if now > signup.end_date:
            raise ValueError("报名已结束")

        # 检查报名人数限制
        current_count = await EnrollmentRecord.filter(signup_id=enrollment_data.signup_id, is_deleted=False).count()
        if current_count >= signup.max_capacity:
            raise ValueError("报名人数已满")

        # 检查是否重复报名
        existing = await EnrollmentRecord.get_or_none(
            signup_id=enrollment_data.signup_id,
            student_id=enrollment_data.student_id,
            is_deleted=False
        )
        if existing:
            raise ValueError("已经报名过此课程")

        try:
            enrollment = await EnrollmentRecord.create(
                signup_id=enrollment_data.signup_id,
                student_id=enrollment_data.student_id
            )

            # 更新课程报名人数
            course = await signup.course
            await course.update_from_dict({"enrollment_count": current_count + 1})
            await course.save()

            return enrollment
        except IntegrityError:
            raise ValueError("报名失败，请重试")

    @staticmethod
    async def get_by_id(enrollment_id: int) -> Optional[EnrollmentRecord]:
        """根据ID获取报名记录"""
        return await EnrollmentRecord.get_or_none(id=enrollment_id, is_deleted=False)

    @staticmethod
    async def get_by_id_with_details(enrollment_id: int) -> Optional[EnrollmentRecordWithDetailsResponse]:
        """根据ID获取报名记录详细信息"""
        enrollment = await EnrollmentRecord.get_or_none(id=enrollment_id, is_deleted=False).prefetch_related(
            'student',
            'signup__course'
        )

        if not enrollment:
            return None

        student = await enrollment.student
        signup = await enrollment.signup
        course = await signup.course

        return EnrollmentRecordWithDetailsResponse(
            id=enrollment.id,
            signup_id=enrollment.signup_id,
            student_id=enrollment.student_id,
            signup_time=enrollment.signup_time,
            student_name=student.name,
            student_phone=student.phone,
            course_title=course.title,
            signup_start_date=signup.start_date,
            signup_end_date=signup.end_date
        )

    @staticmethod
    async def get_list(
            page: int = 1,
            page_size: int = 10,
            signup_id: Optional[int] = None,
            student_id: Optional[int] = None,
            course_id: Optional[int] = None
    ) -> Tuple[List[EnrollmentRecordWithDetailsResponse], int]:
        """获取报名记录列表"""
        query = EnrollmentRecord.filter(is_deleted=False)

        # 按报名筛选
        if signup_id:
            query = query.filter(signup_id=signup_id)

        # 按学员筛选
        if student_id:
            query = query.filter(student_id=student_id)

        # 按课程筛选
        if course_id:
            query = query.filter(signup__course_id=course_id)

        # 计算总数
        total = await query.count()

        # 分页查询
        enrollments = await query.prefetch_related(
            'student',
            'signup__course'
        ).offset((page - 1) * page_size).limit(page_size).order_by('-signup_time')

        # 构造响应数据
        result = []
        for enrollment in enrollments:
            student = await enrollment.student
            signup = await enrollment.signup
            course = await signup.course

            result.append(EnrollmentRecordWithDetailsResponse(
                id=enrollment.id,
                signup_id=enrollment.signup_id,
                student_id=enrollment.student_id,
                signup_time=enrollment.signup_time,
                student_name=student.name,
                student_phone=student.phone,
                course_title=course.title,
                signup_start_date=signup.start_date,
                signup_end_date=signup.end_date
            ))

        return result, total

    @staticmethod
    async def delete(enrollment_id: int) -> bool:
        """删除报名记录（取消报名）"""
        enrollment = await EnrollmentRecord.get_or_none(id=enrollment_id, is_deleted=False)
        if not enrollment:
            return False

        # 获取相关信息用于更新计数
        signup = await SignUp.get(id=enrollment.signup_id, is_deleted=False)
        course = await signup.course
        current_count = await EnrollmentRecord.filter(signup_id=enrollment.signup_id, is_deleted=False).count()
        enrollment.is_deleted = True
        await enrollment.save(update_fields=["is_deleted"])

        # 更新课程报名人数
        await course.update_from_dict({"enrollment_count": max(0, current_count - 1)})
        await course.save()

        return True

    @staticmethod
    async def get_by_student_and_signup(student_id: int, signup_id: int) -> Optional[EnrollmentRecord]:
        """根据学员ID和报名ID获取报名记录"""
        return await EnrollmentRecord.get_or_none(
            student_id=student_id,
            signup_id=signup_id,
            is_deleted=False
        )
